package cn.com.hhrcw.sms.service.impl;

import cn.com.hhrcw.sms.entity.SysSmsTemplate;
import cn.com.hhrcw.sms.mapper.SysSmsTemplateMapper;
import cn.com.hhrcw.sms.service.DictEnum.SEND_RESULT;
import cn.com.hhrcw.sms.service.ISysSmsTemplateService;
import cn.com.hhrcw.sms.service.SendMain;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author lixingxing
 * @since 2020-08-12
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class SysSmsTemplateServiceImpl extends ServiceImpl<SysSmsTemplateMapper, SysSmsTemplate> implements ISysSmsTemplateService {

    @Value("${jeecg.sms.url}")
    private String url;

    @Value("${jeecg.sms.appId}")
    private String appId;

    @Value("${jeecg.sms.type}")
    private String type;

    @Value("${jeecg.sms.ddType}")
    private String ddType;

    @Value("${spring.mail.username}")
    private String form;

    @Value("${spring.mail.nickname}")
    private String nickname;

    @Value("${fake.sms.code}")
    private String fakeSmsCode;

    @Value("${fake.sms.phone}")
    private String fakeSmsPhone;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private JavaMailSender mailSender;

    /**
     * 发送短信验证码
     *
     * @param mobile
     * @return
     */
    @Override
    public boolean sendSms(String sendType, String[] mobile) {
        mobile = this.formatMobile(mobile);
        LambdaQueryWrapper<SysSmsTemplate> wrapper = new LambdaQueryWrapper<SysSmsTemplate>()
            .eq(SysSmsTemplate::getTemplateCode, "SEND_VERIFY_CODE").eq(SysSmsTemplate::getTemplateType, 1);
        SysSmsTemplate template = this.baseMapper.selectOne(wrapper);
        String random = RandomStringUtils.randomNumeric(6);
        Map<String, Object> parameters = Maps.newHashMap();

        parameters.put("code", random);

        String text = simpleTemplate(template.getTemplateContent(), parameters);
        log.info(text);
        parameters.clear();
        String code = "-1";
        //尝试造假
        if (StringUtils.isNotBlank(this.fakeSmsCode) && !code.equals(this.fakeSmsCode) && StringUtils.isNotBlank(this.fakeSmsPhone) && this.fakeSmsPhone.contains(mobile[0])) {
            log.warn("{}造假验证码为：{}", mobile[0], this.fakeSmsCode);
            switch (sendType) {
                case "person":
                    redisTemplate.opsForValue().set("SEND_VERIFY_CODE_PERSON_:" + mobile[0], fakeSmsCode, 5, TimeUnit.MINUTES);
                    break;
                case "ent":
                    redisTemplate.opsForValue().set("SEND_VERIFY_CODE_ENT_:" + mobile[0], fakeSmsCode, 5, TimeUnit.MINUTES);
                    break;
                case "admin":
                    redisTemplate.opsForValue().set("SEND_VERIFY_CODE_ADMIN_:" + mobile[0], fakeSmsCode, 5, TimeUnit.MINUTES);
                    break;
                default:
                    break;
            }
            return true;
        }
        String phone = mobile[0];
        parameters.put("type", type);
        parameters.put("appId", appId);
        parameters.put("mobiles", mobile);
        parameters.put("content", text);
        log.info("短信验证码发送:" + url);
        log.info("短信验证码:" + random);
        //多线程为了立刻向接口返回结果
        ThreadUtil.execute(() -> {
//            ResponseEntity<Integer> str = restTemplate.postForEntity(url, parameters, Integer.class);
            String resultCode = SendMain.sendSmsV1(text,phone);
            if (SEND_RESULT.OK.getCode().equals(resultCode)) {
                switch (sendType) {
                    case "person":
                        redisTemplate.opsForValue().set("SEND_VERIFY_CODE_PERSON_:" + phone, random, 5, TimeUnit.MINUTES);
                        break;
                    case "ent":
                        redisTemplate.opsForValue().set("SEND_VERIFY_CODE_ENT_:" + phone, random, 5, TimeUnit.MINUTES);
                        break;
                    case "admin":
                        redisTemplate.opsForValue().set("SEND_VERIFY_CODE_ADMIN_:" + phone, random, 5, TimeUnit.MINUTES);
                        break;
                    default:
                        break;
                }
            } else {
                Assert.isTrue(false, "发送失败");
            }
        });

        return true;

    }

    /**
     * 发送短信消息
     *
     * @param mobile
     * @return
     */
    @Override
    public boolean sendSms(String[] mobile, String content) {

        try {

            mobile = this.formatMobile(mobile);

            Map<String, Object> parameters = Maps.newHashMap();

            String text = content;
            log.info(text);
            String phone = mobile[0];
            String sendContent = Jsoup.clean(text, Whitelist.none()).replaceAll("&nbsp;", "");
            parameters.put("type", type);
            parameters.put("appId", appId);
            parameters.put("mobiles", mobile);
            parameters.put("content", sendContent);
            log.info("短信消息发送:" + url);
            ThreadUtil.execute(() -> {
//                ResponseEntity<Integer> str = restTemplate.postForEntity(url, parameters, Integer.class);
                String resultCode = SendMain.sendSmsV1(sendContent,phone);
                log.info("mobile:{}  content :{}  sendSms method:{}",phone,content,resultCode);
                Assert.isTrue(resultCode.equals(SEND_RESULT.OK.getCode()), "发送失败");
            });
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return true;
    }

    /**
     * 发送钉钉消息
     *
     * @param mobile
     * @return
     */
    @Override
    public boolean sendddSms(String[] mobile, String content, String msgType) {

        try {

            mobile = this.formatMobile(mobile);

            Map<String, Object> parameters = Maps.newHashMap();

            String text = content;
            log.info(text);

            parameters.put("type", ddType);
            parameters.put("appId", appId);
            parameters.put("phones", mobile);
            parameters.put("content", text);
            parameters.put("msgtype", msgType);
            log.info("钉钉消息发送:" + url);
            ResponseEntity<String> str = restTemplate.postForEntity(url, parameters, String.class);
            if (str.getStatusCode() == HttpStatus.OK) {
                log.info("钉钉消息发送成功:" + url);
            } else {
                Assert.isTrue(false, "发送失败");
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return true;
    }

    /**
     * 发送消息
     *
     * @param map
     * @return
     */
    @Override
    public String sendNews(String code, Map<String, Object> map) {
        LambdaQueryWrapper<SysSmsTemplate> wrapper = new LambdaQueryWrapper<SysSmsTemplate>().eq(SysSmsTemplate::getTemplateCode, code)
            .eq(SysSmsTemplate::getTemplateType, 1);
        SysSmsTemplate template = baseMapper.selectOne(wrapper);

        return simpleTemplate(template.getTemplateContent(), map);
    }

    /**
     * 获得头
     *
     * @param code
     * @param
     * @return
     */
    @Override
    public String getTittle(String code) {
        LambdaQueryWrapper<SysSmsTemplate> wrapper = new LambdaQueryWrapper<SysSmsTemplate>().eq(SysSmsTemplate::getTemplateCode, code).eq(SysSmsTemplate::getTemplateType, 1);
        SysSmsTemplate template = baseMapper.selectOne(wrapper);

        return template.getTemplateName();
    }

    @Override
    @Async
    public void sendEmail(String code, Map<String, Object> parameters, String... to) {
        LambdaQueryWrapper<SysSmsTemplate> wrapper = new LambdaQueryWrapper<SysSmsTemplate>().eq(SysSmsTemplate::getTemplateCode, code).eq(SysSmsTemplate::getTemplateType, 2);
        SysSmsTemplate template = this.baseMapper.selectOne(wrapper);
        String text = simpleTemplate(template.getTemplateContent(), parameters);
        this.sendEmail(text, template.getTemplateName(), to);
    }

    @Override
    @Async
    public void sendEmail(String code, Map<String, Object> parameters, File file, String... to) {
        LambdaQueryWrapper<SysSmsTemplate> wrapper = new LambdaQueryWrapper<SysSmsTemplate>().eq(SysSmsTemplate::getTemplateCode, code).eq(SysSmsTemplate::getTemplateType, 2);
        SysSmsTemplate template = this.baseMapper.selectOne(wrapper);
        String text = simpleTemplate(template.getTemplateContent(), parameters);
        this.sendEmail(text, template.getTemplateName(), file, to);
    }

    @Override
    @Async
    public void sendEmail(String text, String subject, String... to) {
        SimpleMailMessage mimeMessage = new SimpleMailMessage();
        mimeMessage.setFrom(StrUtil.format("{}<{}>", nickname, form));
        mimeMessage.setTo(to);
        mimeMessage.setSubject(subject);
        mimeMessage.setText(text);
        mailSender.send(mimeMessage);
    }

    @Override
    @SneakyThrows
    @Async
    public void sendEmail(String text, String subject, File file, String... to) {
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
        messageHelper.setFrom(StrUtil.format("{}<{}>", nickname, form));
        messageHelper.setTo(to);
        messageHelper.setSubject(subject);
        messageHelper.setText(text, true);
        if (FileUtil.isNotEmpty(file)) {
            messageHelper.addAttachment(file.getName(), file);
        }
        mailSender.send(mimeMessage);
    }

    Pattern pattern = Pattern.compile("\\$\\{([^}]+)}");

    public String simpleTemplate(String templateStr, Map<String, ?> data, String... defaultNullReplaceVals) {
        if (templateStr == null) {
            return null;
        }

        if (data == null) {
            data = Collections.emptyMap();
        }

        String nullReplaceVal = defaultNullReplaceVals.length > 0 ? defaultNullReplaceVals[0] : "";

        StringBuffer newValue = new StringBuffer(templateStr.length());

        Matcher matcher = pattern.matcher(templateStr);

        while (matcher.find()) {
            String key = matcher.group(1);
            String r = data.get(key) != null ? data.get(key).toString() : nullReplaceVal;
            //这个是为了替换windows下的文件目录在java里用\\表示
            matcher.appendReplacement(newValue, r.replaceAll("\\\\", "/"));
        }

        matcher.appendTail(newValue);

        return newValue.toString();
    }
}
